package myepoll

import (
	"net"
	"server_cluster/common/config"
	"server_cluster/common/logger"
	"sync"
	"syscall"
)

const (
	CONN_TYPE_CLIENT		= 1 // 客户端连接
	CONN_TYPE_GATE			= 2 // 网关连接
	CONN_TYPE_LOGIC			= 3 // 逻辑服连接
	CONN_TYPE_BATTLE		= 4 // 战斗服连接
	CONN_TYPE_CHAT_ROOT		= 5 // 聊天根服连接 全服仅一台
)

var Eps EpollServer

// var Eps_back EpollServer

type Conn struct {
	Socket  *net.TCPConn
	Timeout int64
	Site    int32
	Total   int8  // 发包数量
	Type    int8  // 连接类型
	Sid     int16 // 服务器id
}

type Server struct {
	Fd    int32
	Stock int32
}

type EpollServer struct {
	Events     []syscall.EpollEvent
	EpollFd    int
	Fds        sync.Map
	server_map map[int8]map[int16]*Server //type:id:server
}

func (s *EpollServer) GetServerMap() map[int8]map[int16]*Server {
	if s.server_map == nil {
		s.server_map = make(map[int8]map[int16]*Server, 3)
	}

	return s.server_map
}

func (s *EpollServer) GetServerMapByType(Type int8) map[int16]*Server {
	tmp := s.GetServerMap()
	if tmp[Type] == nil {
		tmp[Type] = make(map[int16]*Server, 10)
	}
	return tmp[Type]
}

func (s *EpollServer) SetServerMapFd(Type int8, sid int16, fd int32, stock int32) {
	server := &Server{
		Fd:    fd,
		Stock: stock,
	}
	s.GetServerMapByType(Type)[sid] = server
}

func (s *EpollServer) SetServerMapStock(Type int8, sid int16, stock int32) {
	s.GetServerMapByType(Type)[sid].Stock = stock
}

func (s *EpollServer) DeleteServerMap(Type int8, sid int16) {
	delete(s.GetServerMapByType(Type), sid)
}

func (s *EpollServer) InitServer(user_max int32) error {
	var err error
	s.Events = make([]syscall.EpollEvent, user_max)
	s.EpollFd, err = syscall.EpollCreate1(0)
	if err != nil {
		return err
	}
	return nil
}

func (s *EpollServer) AddFd(fd int32, conn *net.TCPConn, timeout int64, Type int8, sid int16, stock int32) error {
	var err error
	err = syscall.SetNonblock(int(fd), true)
	if err != nil {
		logger.Error("set nonblock error", err)
		return err
	}
	ev := syscall.EpollEvent{
		Fd: fd,
		// Events:syscall.EPOLLIN | syscall.EPOLLOUT,
		Events: syscall.EPOLLIN,
	}
	err = syscall.EpollCtl(s.EpollFd, syscall.EPOLL_CTL_ADD, int(fd), &ev)
	if err != nil {
		logger.Error("epoll ctl error", err)
		return err
	}
	tmp := &Conn{
		Socket:  conn,
		Timeout: timeout + config.TIME_OUT_MIN,
		Site:    -1,
		Total:   0,
		Type:    Type,
		Sid:     sid,
	}
	s.Fds.Store(fd, tmp)
	if Type == CONN_TYPE_CLIENT {
		return nil
	}
	s.SetServerMapFd(Type, sid, fd, stock)
	return nil
}

func (s *EpollServer) Wait(ms int) ([]syscall.EpollEvent, error) {
	if ms < 0 {
		// 阻塞
		ms = -1
	}
	nEvents, err := syscall.EpollWait(s.EpollFd, s.Events, ms)
	if err != nil {
		return nil, err
	}
	return s.Events[:nEvents], nil
}

func IsReadableEvent(event uint32) bool {
	return event&syscall.EPOLLIN != 0
}

func (s *EpollServer) GetConnByFd(fd int32) *Conn {
	tmp, ok := s.Fds.Load(fd)
	if !ok {
		return nil
	}
	conns, ok := tmp.(*Conn)
	if !ok {
		return nil
	}
	return conns
}

func (s *EpollServer) CleanConn(fd int32) {
	conns := s.GetConnByFd(fd)
	if conns != nil {
		conns.Socket.Close()
	}
	s.Fds.Delete(fd)
}

func (s *EpollServer) GetFdByMap(Type int8, sid int16) int32 {
	server, ok := s.GetServerMapByType(Type)[sid]
	if !ok {
		return -1
	}
	return server.Fd
}

func (s *EpollServer) CleanServerConn(Type int8, sid int16) {
	server_map := s.GetServerMapByType(Type)
	server, ok := server_map[sid]
	if !ok {
		return
	}
	s.CleanConn(server.Fd)
	delete(server_map, sid)
}
